package com.example.auv_660.network.udp;

import android.util.Log;

import com.example.auv_660.MainActivity;
import com.example.auv_660.auvorderload.OrderLoad;
import com.example.auv_660.order.SendReceiveOrder;
import com.example.auv_660.util.Constants;
import com.example.auv_660.util.ThreadPool;

import java.io.BufferedWriter;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.ServiceLoader;

public enum HFUDPBuild {
    INSTANCE;

    private HFUDPClient hfudpClient;

    HFUDPBuild()
    {
        hfudpClient = new HFUDPClient();
    }

    public HFUDPClient getHFUdpClient()
    {
        return hfudpClient;
    }

    private static ArrayList<OrderLoad> instances;

    static
    {
        // ServiceLoader.load执行时，会到META-INF/services的配置文件中寻找这个接口对应得实现类的全路径名，然后使用反射去生成一个无参的实例
        ServiceLoader<OrderLoad> serviceLoader = ServiceLoader.load(OrderLoad.class);
        instances = new ArrayList<>();

        for (OrderLoad service : serviceLoader)
        {
            instances.add(service);
        }

        for (int i = 0; i < instances.size() - 1; i++)
        {
            instances.get(i).setNextOrder(instances.get(i + 1));
        }
    }

    public class HFUDPClient
    {
        private static final String TAG = "HFUDPClient";
        private static final int UDP_CLIENT_PORT = 8911;
        private static final int BUFFER_LENGTH = 10240;
        private static final double MEMORY_USE_RATIO = 0.1;
        private byte[] byteBuffer = new byte[BUFFER_LENGTH];
        private int receiveBuffer;
        private DatagramSocket socket;
        private DatagramPacket receiveData;
        private boolean threadRunning;
        private BufferedWriter bw;
        private MainActivity mainActivity;

        private HFUDPClient()
        {
            receiveBuffer = (int) (Runtime.getRuntime().freeMemory() * MEMORY_USE_RATIO);
            threadRunning = false;
            mainActivity = MainActivity.getInstance();
        }

        public void udpWorker()
        {
            enableUDPResource();
            SendReceiveOrder.deviceInit();
            receiveMessage();
        }

        private void enableUDPResource()
        {
            try
            {
                socket = new DatagramSocket(UDP_CLIENT_PORT);
                socket.setReceiveBufferSize(receiveBuffer);
                receiveData = new DatagramPacket(byteBuffer, BUFFER_LENGTH);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            threadRunning = true;
        }

        public void sendMessage(final String message)
        {
            ThreadPool.INSTANCE.getThreadPoolProxy().joinTask(new Runnable()
            {
                @Override
                public void run()
                {
                    try
                    {
                        DatagramPacket datagramPacket = new DatagramPacket(message.getBytes(), message.getBytes().length,
                                InetAddress.getByName(Constants.SERVER_IP), Constants.UDP_SERVER_PORT);
                        socket.send(datagramPacket);
                    }
                    catch (UnknownHostException e)
                    {
                        e.printStackTrace();
                    }
                    catch (IOException e)
                    {
                        e.printStackTrace();
                    }
                }
            });
        }

        private void receiveMessage()
        {
            new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    if (socket == null)
                    {
                        releaseUDPResource();
                        Log.e(TAG, "Can not initialize UDP client");
                        return;
                    }
                    while (threadRunning)
                    {
                        try
                        {
                            socket.receive(receiveData);
                        }
                        catch (IOException e)
                        {
                            e.printStackTrace();
                        }
                        if (receiveData == null || receiveData.getLength() == 0)
                        {
                            continue;
                        }
                        else
                        {

                            byte[] arr = receiveData.getData();
                            int len = receiveData.getLength();
                            String order = new String(arr, 0, len);
                            SendReceiveOrder.receiveOrder(order);
                        }
                    }
                }
            }).start();
        }

        private void releaseUDPResource()
        {
            threadRunning = false;
            if (socket != null)
            {
                socket.close();
                socket = null;
            }
            receiveData = null;
            ThreadPool.INSTANCE.getThreadPoolProxy().shutDownCommonPool();
        }
    }
}